package cn.wzut.edut.jwt;

import cn.wzut.edut.dao.inf.User;
import cn.wzut.edut.dao.pojo.table.SysUser;
import cn.wzut.edut.exception.ServiceException;
import cn.wzut.edut.service.SysService;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * token拦截器类
 * by 叶庭辉
 */
@Component
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {

    @Autowired
    User login;

    @Autowired
    SysService sysService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 从http请求头中取出token
        String token = request.getHeader("token");
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        // 检查方法上是否有passtoken注释，有则跳过认证
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }

        // 判断token是否为空
        if (token == null) {
            throw new ServiceException(-1, "身份信息无效，请重新登录");
        }

        // 解析token
        DecodedJWT decode = JWTUtils.decode(token);

        // 获取token中的userid
        String userId;
        try {
            userId = decode.getClaim("userid").asString();
        } catch (JWTDecodeException e) {
            throw new ServiceException(-1, "身份信息未授权");
        }

        // 验证token信息真伪性
        SysUser sysUser = login.selectUserInId(userId);
        if (sysUser == null) {
            throw new ServiceException(-1, "用户不存在或已被删除，请重新登录");
        }

        // 验证用户是否拥有权限
        String servletPath = request.getServletPath();
        if(!isPermit(userId, servletPath)){
            throw new ServiceException(-1, "用户权限不足，拒绝访问");
        }

        // 记录用户的访问日志
        log.info(String.format("requestInfo: uid: %s, servletPath: %s, date: %s", userId, servletPath,
                new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z").format(new Date(System.currentTimeMillis()))));

        // 获取当前userid并存放至CurrentUserInfo中
        CurrentUserInfo currentUserInfo = new CurrentUserInfo(userId);

        // 为CurrentUserMethodArgumentResolver中的currentUserInfo设置用户信息
        request.setAttribute("currentUserInfo", currentUserInfo);

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }

    /**
     * 权限判断
     * @param userId
     * @param servletPath
     * @return
     */
    public boolean isPermit(String userId, String servletPath){
        String[] path = servletPath.split("/");

        List<String> res_urls = sysService.getResUrlsByUser(userId);

        StringBuilder sb = new StringBuilder();
        // 查询用户是否拥有相关权限
        for(int i = 0; i < path.length; i++){
            sb.append(path[i]); //构造res_url
            if(res_urls.stream().anyMatch(url -> sb.toString().equals(url))){
                return true;
            }
            sb.append("/");
        }
        return false;
    }

}
